package com.xu.cloud.common.filter;

import com.xu.cloud.common.constant.HttpConstant;
import com.xu.cloud.common.constant.OrderConstant;
import com.xu.cloud.common.trace.SimpleTraceIdContext;
import com.xu.cloud.common.trace.TraceIdContext;
import com.xu.cloud.common.trace.TraceIdContextHolder;
import com.xu.cloud.common.trace.UUIDTraceIdContext;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.core.annotation.Order;
import org.springframework.util.StringUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * traceId上下文过滤器
 *
 * @author xuguan
 * @since 2025/1/8
 */
@Order(value = OrderConstant.TRACE_ID_CONTEXT_FILTER_ORDER)
@WebFilter(description = "traceId上下文过滤器", urlPatterns = "/*")
public class TraceIdContextFilter extends BaseRequestFilter {

    private final ObjectProvider<TraceIdContext> traceIdContextProvider;

    public TraceIdContextFilter(ObjectProvider<TraceIdContext> traceIdContextProvider) {
        this.traceIdContextProvider = traceIdContextProvider;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        final TraceIdContext traceIdContext;
        final String traceId = request.getHeader(HttpConstant.HEADER_TRACE_ID);
        if (StringUtils.hasText(traceId)) {
            traceIdContext = new SimpleTraceIdContext(traceId);
        } else {
            traceIdContext = traceIdContextProvider.getIfAvailable(UUIDTraceIdContext::new);
        }

        TraceIdContextHolder.setTraceIdContext(traceIdContext);

        try {
            filterChain.doFilter(request, response);
        } finally {
            TraceIdContextHolder.removeTraceIdContext();
        }
    }
}
